Skip to content

Stop using an introduction node in blinded message paths#4647

Merged
jkczyz merged 1 commit into
lightningdevkit:mainfrom
TheBlueMatt:2026-06-no-bolt12-privacy
Jun 8, 2026
Merged

Stop using an introduction node in blinded message paths#4647
jkczyz merged 1 commit into
lightningdevkit:mainfrom
TheBlueMatt:2026-06-no-bolt12-privacy

Conversation

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

lnd is preparing to ship a release with opt-in onion messages without support for forwarding onion messages from non-channel peers. This breaks the common BOLT 12 OM flow today where we direct-connect to the blinded path introduction point and send the invoice_request without a channel. For CLN it turns out this is fine as they never select a peer for their introduction point at all. However, for LDK this would break existing nodes as nodes might now pick an lnd peer as an introduction node but it won't forward the onion message.

For now, we just drop the separate introduction point selection and just always use ourselves as an introduction point (assuming we're an announced node).

This should also have the side-effect of making offers marginally more robust, which may be worth it, even if it sucks to drop any pretense of privacy.

@ldk-reviews-bot

ldk-reviews-bot commented May 29, 2026

Copy link
Copy Markdown

👋 Thanks for assigning @jkczyz as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@TheBlueMatt TheBlueMatt added this to the 0.3 milestone May 29, 2026
Comment thread lightning/src/onion_message/messenger.rs Outdated

// Prefer using non-Tor nodes with the most channels as the introduction node.
peer_info.sort_unstable_by(|(_, a_tor_only, a_channels), (_, b_tor_only, b_channels)| {
a_tor_only.cmp(b_tor_only).then(a_channels.cmp(b_channels).reverse())

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly, the Tor-only component of this sort is now effectively dead — since the Tor-only filter above is a no-op (see comment there), Tor-only nodes do still get sorted to the back, but they're never excluded. If excluding Tor-only nodes for unannounced recipients isn't intended, the is_tor_only tracking and sorting could be cleaned up for clarity (just sort by channel count).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't true. If we have more than MAX_PATHS peers and are unannounced the sorting here will result in dropping the tor-only peers.

@ldk-claude-review-bot

ldk-claude-review-bot commented May 29, 2026

Copy link
Copy Markdown
Collaborator

I've thoroughly reviewed the entire PR diff, checked all the changed code paths, verified removed imports and functions are truly unused, and confirmed the logic in both the announced and unannounced recipient branches is correct.

My prior review comments (dead Tor-only filter and misleading comment in the unannounced branch) were addressed in a subsequent commit.

No new issues found.

@ldk-reviews-bot ldk-reviews-bot requested a review from jkczyz May 29, 2026 15:56
@ldk-reviews-bot

Copy link
Copy Markdown

🔔 1st Reminder

Hey @jkczyz! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

Comment on lines +640 to +642
} else {
vec![]
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given we can return more than one path, couldn't we return the 1-hop path (plus dummy hops) in addition to the multi-hop paths? Senders would try all paths, or at least retry over different paths if they don't get a response over the paths requiring a direct connection with an LND node.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is the BOLT 12 offer creation stuff will pick one path at random (well, currently just the first path, but I'm not sure we want to rely on that at the messagerouter level). Doing this would indeed give us back some privacy for other usecases, but I'm not sure we care as much about hose vs BOLT 12 offers :/.

@TheBlueMatt TheBlueMatt requested a review from jkczyz June 8, 2026 13:29

@jkczyz jkczyz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, please squash.

lnd is preparing to ship a release with opt-in onion messages
without support for forwarding onion messages from non-channel
peers. This breaks the common BOLT 12 OM flow today where we
direct-connect to the blinded path introduction point and send the
`invoice_request` without a channel. For CLN it turns out this is
fine as they never select a peer for their introduction point at
all. However, for LDK this would break existing nodes as nodes
might now pick an lnd peer as an introduction node but it won't
forward the onion message.

For now, we just drop the separate introduction point selection and
just always use ourselves as an introduction point (assuming we're
an announced node).

This should also have the side-effect of making offers marginally
more robust, which may be worth it, even if it sucks to drop any
pretense of privacy.
@TheBlueMatt TheBlueMatt force-pushed the 2026-06-no-bolt12-privacy branch from 39e42bc to 8c08a30 Compare June 8, 2026 20:23
@TheBlueMatt

Copy link
Copy Markdown
Collaborator Author

Squashed without further changes.

@TheBlueMatt TheBlueMatt requested a review from jkczyz June 8, 2026 20:23
@jkczyz

jkczyz commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

ci/ci-tests.sh and ci/check-each-commit.sh upstream/main pass locally using RUSTUP_TOOLCHAIN=1.75.0.

@jkczyz jkczyz merged commit 3a48e75 into lightningdevkit:main Jun 8, 2026
1 check passed
@vincenzopalazzo

Copy link
Copy Markdown
Contributor

I am wondering if for the !is_recipient_announced, we want to have a setting in the config to set the pubkey or the channel ID to use to avoid picking an LND node?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants